Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: create common graphql error handler #384

Open
wants to merge 17 commits into
base: main
Choose a base branch
from

Conversation

kshitij-k-osmosys
Copy link
Contributor

@kshitij-k-osmosys kshitij-k-osmosys commented Jan 17, 2025

Portal PR Checklist

Task Link

OSXT-234

Pre-requisites

  • I have gone through the Contributing guidelines for Submitting a Pull Request (PR) and ensured that this is not a duplicate PR.
  • I have performed unit testing for the new feature added or updated to ensure the new features added are working as expected.
  • I have performed preliminary testing to ensure that any existing features are not impacted and any new features are working as expected as a whole.

PR Details

PR details have been updated as per the given format (see below)

  • PR title adheres to the format specified in guidelines (e.g., feat: add admin login page)
  • Description has been added
  • Related changes have been added (optional)
  • Screenshots have been added (optional, may include unit testing screenshots as well)
  • Pending actions have been added (optional)
  • Any other additional notes have been added (optional)

Additional Information

  • Appropriate label(s) have been added (ready for review should be added if the PR is ready to be reviewed)
  • Assignee(s) and reviewer(s) have been added (optional)

Note: Reviewer should ensure that the checklist and description have been populated and followed correctly, and the PR should be merged only after resolving all conversations and verifying that CI checks pass.


Description:

Create common graphql error handler validateApolloErrors(response)
Add the error handler before service functions process data
OnInitialization, applications already has error handling here so did not add it

Summary by CodeRabbit

Release Notes

  • New Features

    • Added advanced provider and notification filtering capabilities
    • Introduced new GraphQL queries for retrieving providers and notifications
    • Enhanced dropdown selection for filtering notifications
  • Improvements

    • Improved error handling for GraphQL queries
    • Strengthened type safety in service methods
    • Updated notification loading logic to support more flexible filtering
  • Bug Fixes

    • Refined application and notification data retrieval processes

@kshitij-k-osmosys kshitij-k-osmosys self-assigned this Jan 17, 2025
Copy link

coderabbitai bot commented Jan 17, 2025

Walkthrough

The pull request introduces a comprehensive enhancement to the notifications and providers management system. The changes focus on improving data retrieval, error handling, and user interface for managing providers and notifications. New GraphQL queries have been added to fetch providers and notifications together, with support for both active and archived notifications. The modifications include updates to services, components, and models to support more flexible and type-safe data fetching and filtering.

Changes

File Change Summary
apps/portal/src/app/graphql/graphql.queries.ts Added two new GraphQL queries: GetProvidersAndNotifications and GetProvidersAndArchivedNotifications
apps/portal/src/app/graphql/graphql.service.ts Added validateApolloErrors method for improved error handling
apps/portal/src/app/views/applications/applications.service.ts Updated getApplications method with explicit type annotations
apps/portal/src/app/views/notifications/notifications.component.html Replaced channel type dropdown with provider dropdown
apps/portal/src/app/views/notifications/notifications.component.ts Refactored methods to load providers and notifications, added new filtering logic
apps/portal/src/app/views/notifications/notifications.service.ts Updated methods with type annotations and added Apollo error validation
apps/portal/src/app/views/providers/provider.model.ts Added Provider and ProviderAndNotificationResponse interfaces
apps/portal/src/app/views/providers/providers.service.ts Created new service for fetching providers and notifications

Sequence Diagram

sequenceDiagram
    participant User
    participant NotificationsComponent
    participant ProvidersService
    participant GraphQLService
    
    User->>NotificationsComponent: Select Application
    NotificationsComponent->>ProvidersService: getProvidersAndNotifications()
    ProvidersService->>GraphQLService: Execute GraphQL Query
    GraphQLService-->>ProvidersService: Return Query Results
    ProvidersService-->>NotificationsComponent: Provide Providers and Notifications
    NotificationsComponent->>User: Display Providers and Notifications
Loading

Poem

🐰 Hop, hop, through queries so bright,
Providers and notifications take flight!
GraphQL magic, errors now tamed,
A rabbit's code, precisely framed! 🚀
Filtering fun, with style and grace,
Our portal leaps to a new embrace! 🌈

✨ Finishing Touches
  • 📝 Generate Docstrings (Beta)

Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

❤️ Share
🪧 Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>, please review it.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai gather interesting stats about this repository and render them as a table. Additionally, render a pie chart showing the language distribution in the codebase.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (Invoked using PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai generate docstrings to generate docstrings for this PR. (Beta)
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Other keywords and placeholders

  • Add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.
  • Add @coderabbitai summary to generate the high-level summary at a specific location in the PR description.
  • Add @coderabbitai anywhere in the PR title to generate the title automatically.

CodeRabbit Configuration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

@kshitij-k-osmosys kshitij-k-osmosys marked this pull request as ready for review January 31, 2025 09:44
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

🔭 Outside diff range comments (1)
apps/portal/src/app/views/applications/applications.service.ts (1)

Line range hint 22-38: Use the common error handler for consistency.

The service should use the new validateApolloErrors method for consistent error handling across the application.

Apply this change:

   getApplications(variables: unknown, inputToken: string): Observable<ApplicationResponse> {
     return this.graphqlService.query(GetApplications, variables, inputToken).pipe(
       map((response: ApolloQueryResult<GetApplicationsResponse>) => {
+        this.graphqlService.validateApolloErrors(response);
         const applicationArray = response.data?.applications.applications;

         const applicationResponseObject: ApplicationResponse = {
           applications: applicationArray,
           total: response.data?.applications.total,
           offset: response.data?.applications.offset,
           limit: response.data?.applications.limit,
-          errors: response.errors || null,  // Remove this as errors are now handled by validateApolloErrors
         };
         return applicationResponseObject;
       }),
       catchError((error) => {
         const errorMessage: string = error.message;
         throw new Error(errorMessage);
       }),
     );
   }
🧹 Nitpick comments (11)
apps/portal/src/app/views/providers/providers.service.ts (2)

48-95: Consider extracting common code for the archived vs non-archived branches.
The if (archivedNotificationToggle) branch duplicates logic (mapping, error handling, etc.). You could reduce duplication by consolidating transformations in a helper function.

Sample approach:

if (archivedNotificationToggle) {
  // ...
} else {
  // ...
}

+ // Potentially unify repeated logic in a shared callback that converts 
+ // providers and notifications (or archived notifications) to the standard form 
+ // and handles the error and pipe. 

97-120: Catch error objects without losing context.
When catching errors, re-throwing them as new Error objects can lose stack traces or additional info. Consider re-throwing the original error or attaching the original data to preserve debugging context.

apps/portal/src/app/views/notifications/notifications.component.ts (3)

48-48: Initialize providers with stronger type.
If you intend providers to always hold an array of typed provider objects, explicitly declare the array type to improve maintainability and clarity.

- providers = [];
+ providers: { label: string; value: number }[] = [];

Line range hint 102-179: Avoid deeply nested subscriptions in production code.
While this is acceptable, consider organizing load steps so each call unsubscribes properly or merges streams elegantly (e.g., using RxJS switchMap) to reduce the chance of memory leaks.


384-386: Filters in multiple places.
You have multiple filter sets (in loadProvidersAndNotificationsForSelectedApplication and in loadNotificationsLazy). Consider centralizing or reusing filter logic to avoid duplication.

apps/portal/src/app/views/providers/provider.model.ts (1)

1-11: Prefer enumerations where applicable.
channelType and status are typed as number; for maintainability, consider using a TypeScript enum or union for clarity and safer references.

apps/portal/src/app/graphql/graphql.service.ts (1)

63-73: Consider enhancing error types and handling.

The error handler implementation is good but could be improved with more specific error types and additional context.

Consider these enhancements:

-  validateApolloErrors<T>(response: ApolloQueryResult<T>): void {
+  validateApolloErrors<T>(response: ApolloQueryResult<T>): void {
+    interface GraphQLError {
+      code?: string;
+      message: string;
+      path?: readonly (string | number)[];
+    }
+
     if (response.errors && response.errors.length > 0) {
-      const errorMessages = response.errors.map((err) => err.message).join('; ');
+      const errorMessages = response.errors.map((err: GraphQLError) => 
+        `${err.code ? `[${err.code}] ` : ''}${err.message}${err.path ? ` at ${err.path.join('.')}` : ''}`
+      ).join('; ');
       throw new Error(`GraphQL Formatted Error(s): ${errorMessages}`);
     }

     if (response.error) {
-      throw new Error(`Apollo Error: ${response.error.message}`);
+      throw new Error(`Apollo Network Error: ${response.error.message}`);
     }
   }
apps/portal/src/app/graphql/graphql.queries.ts (2)

97-154: Consider using GraphQL fragments to reduce duplication.

The provider and notification field selections are duplicated across queries. Using fragments would improve maintainability.

Consider refactoring to use fragments:

+const ProviderFields = gql`
+  fragment ProviderFields on Provider {
+    applicationId
+    channelType
+    createdOn
+    name
+    providerId
+    status
+    updatedOn
+  }
+`;
+
+const NotificationFields = gql`
+  fragment NotificationFields on Notification {
+    channelType
+    createdBy
+    createdOn
+    data
+    deliveryStatus
+    id
+    result
+    status
+    updatedBy
+    updatedOn
+  }
+`;

 export const GetProvidersAndNotifications = gql`
+  ${ProviderFields}
+  ${NotificationFields}
   query GetProvidersAndNotifications(
     $providerLimit: Int!
     # ... other variables
   ) {
     providers(
       options: {
         # ... options
       }
     ) {
       providers {
-        applicationId
-        channelType
-        # ... other fields
+        ...ProviderFields
       }
       # ... pagination fields
     }
     notifications {
       notifications {
-        channelType
-        createdBy
-        # ... other fields
+        ...NotificationFields
       }
       # ... pagination fields
     }
   }
 `;

156-213: Consider making sort order configurable.

The sort orders are hardcoded (ASC for providers, DESC for notifications). Consider making them configurable via variables.

Consider this enhancement:

 export const GetProvidersAndArchivedNotifications = gql`
   query GetProvidersAndArchivedNotifications(
     $providerLimit: Int!
     $providerOffset: Int!
     $providerFilters: [UniversalFilter!]
+    $providerSortOrder: SortOrder = ASC
     $notificationLimit: Int!
     $notificationOffset: Int!
     $notificationFilters: [UniversalFilter!]
+    $notificationSortOrder: SortOrder = DESC
   ) {
     providers(
       options: {
         limit: $providerLimit
         offset: $providerOffset
         sortBy: "createdOn"
-        sortOrder: ASC
+        sortOrder: $providerSortOrder
         filters: $providerFilters
       }
     )
     # ... rest of the query
   }
 `;
apps/portal/src/app/views/notifications/notifications.service.ts (1)

Line range hint 32-83: Extract common error handling logic.

Both methods have identical error handling logic. Consider extracting it to a private method.

Consider this refactor:

+  private handleGraphQLError(error: Error): never {
+    const errorMessage: string = error.message;
+    throw new Error(errorMessage);
+  }
+
   getNotifications(variables: unknown, inputToken: string): Observable<NotificationResponse> {
     return this.graphqlService.query(GetNotifications, variables, inputToken).pipe(
       map((response: ApolloQueryResult<GetNotificationsResponse>) => {
         this.graphqlService.validateApolloErrors(response);
         // ... rest of the mapping logic
       }),
-      catchError((error) => {
-        const errorMessage: string = error.message;
-        throw new Error(errorMessage);
-      }),
+      catchError(this.handleGraphQLError.bind(this)),
     );
   }

   getArchivedNotifications(variables: unknown, inputToken: string): Observable<NotificationResponse> {
     return this.graphqlService.query(GetArchivedNotifications, variables, inputToken).pipe(
       map((response: ApolloQueryResult<GetArchivedNotificationsResponse>) => {
         this.graphqlService.validateApolloErrors(response);
         // ... rest of the mapping logic
       }),
-      catchError((error) => {
-        const errorMessage: string = error.message;
-        throw new Error(errorMessage);
-      }),
+      catchError(this.handleGraphQLError.bind(this)),
     );
   }
apps/portal/src/app/views/notifications/notifications.component.html (1)

55-57: LGTM! Consider caching providers.

The change to load providers and notifications together is a good improvement. However, since providers data might not change as frequently as notifications, consider caching the providers data to reduce unnecessary API calls.

📜 Review details

Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between c14ba9b and 9060bfc.

📒 Files selected for processing (8)
  • apps/portal/src/app/graphql/graphql.queries.ts (1 hunks)
  • apps/portal/src/app/graphql/graphql.service.ts (1 hunks)
  • apps/portal/src/app/views/applications/applications.service.ts (1 hunks)
  • apps/portal/src/app/views/notifications/notifications.component.html (2 hunks)
  • apps/portal/src/app/views/notifications/notifications.component.ts (9 hunks)
  • apps/portal/src/app/views/notifications/notifications.service.ts (2 hunks)
  • apps/portal/src/app/views/providers/provider.model.ts (1 hunks)
  • apps/portal/src/app/views/providers/providers.service.ts (1 hunks)
🔇 Additional comments (11)
apps/portal/src/app/views/providers/providers.service.ts (3)

1-11: Use consistent import paths or naming if possible.
Everything here looks consistent and follows Angular style norms. No issues found.


12-25: Confirm interfaces reflect actual GraphQL data shape.
These fields, especially optional ones, should reflect how the backend resolves the data. Be sure all properties in GetProviderNotificationResponse exist in the GraphQL schema to prevent runtime errors.


27-40: Align archived notifications interface with GraphQL schema.
Similar to the above comment, ensure GetProviderArchivedNotificationResponse precisely matches the shape of the archived notifications response (naming, optional vs required).

apps/portal/src/app/views/notifications/notifications.component.ts (6)

10-11: Imports look good.
No concerns with these additional imports.


54-55: Selected provider defaults.
Setting selectedProvider to null is fine. Just confirm that no further references cause undefined checks in the template.


87-87: Service injection is consistent.
Good job injecting ProvidersService for use across the component.


93-93: Ensure no stale references to old function name.
Renaming to getApplicationsAndInitializeData() is clear. Just confirm any references to getApplications() or old references are replaced.


228-350: Guard against partial or null data in providerAndNotificationResponse.
When referencing arrays like providers or notifications, ensure you null-check them before mapping to avoid potential runtime errors.


456-505: Check date filter logic inclusivity.
Lines 475–493 show date range filtering. Confirm that shifting dates (like +1 for selectedToDate) meets your inclusive/exclusive logic (e.g., do you want “less than” vs “less than or equal”?).

apps/portal/src/app/views/providers/provider.model.ts (1)

13-23: Interfaces look consistent with the rest of the code.
No issues found. They align with the usage in ProvidersService.

apps/portal/src/app/views/notifications/notifications.component.html (1)

9-11: Verify loadNotificationsLazy implementation for provider filtering.

The dropdown has been updated to use providers instead of channel types. Please ensure that the loadNotificationsLazy method in the component class has been updated to handle the new selectedProvider model correctly.

Run the following script to verify the implementation:

✅ Verification successful

Implementation correctly handles provider filtering

The loadNotificationsLazy method properly integrates with the new provider dropdown through the getCombinedNotificationFilters method, which correctly adds the provider filter when selectedProvider is set.

🏁 Scripts executed

The following scripts were executed for the analysis:

Script:

#!/bin/bash
# Description: Verify that loadNotificationsLazy has been updated to handle selectedProvider.

# Test: Search for loadNotificationsLazy implementation
ast-grep --pattern $'loadNotificationsLazy($params) {
  $$$
}'

Length of output: 63


Script:

#!/bin/bash
# Find the component's TypeScript file
fd "notifications.component.ts" 

# Search for loadNotificationsLazy implementation in TypeScript files
rg "loadNotificationsLazy" -t ts -A 10

Length of output: 2065


Script:

#!/bin/bash
# Get the complete implementation of loadNotificationsLazy
rg "loadNotificationsLazy" -t ts -A 30 apps/portal/src/app/views/notifications/notifications.component.ts

Length of output: 1729


Script:

#!/bin/bash
# Get more context lines to see complete filter construction
rg "loadNotificationsLazy" -t ts -B 5 -A 50 apps/portal/src/app/views/notifications/notifications.component.ts

Length of output: 3365


Script:

#!/bin/bash
# Find the getCombinedNotificationFilters implementation
rg "getCombinedNotificationFilters" -t ts -A 20 apps/portal/src/app/views/notifications/notifications.component.ts

Length of output: 2093

@osm-vishnukyatannawar
Copy link
Member

Keeping this PR on hold.

@kshitij-k-osmosys when you are back kindly resolve conflicts.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants